/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//
*/

#ifndef __UMC_AVS_DEC_BIT_STREAM_H
#define __UMC_AVS_DEC_BIT_STREAM_H

#include "ippdefs.h"
#include "umc_avs_context.h"
#include "umc_avs_consts.h"

namespace UMC
{

extern
Ipp8u AVSDecMoreZerosTable[128];

//
// Entropy decoding functions
//

inline
void InitializeDecBitStream(AVS_BIT_STREAM_CONTEXT *pCtx,
                            const Ipp32u *pSrc,
                            size_t srcSize)
{
    pCtx->src = pSrc;
    pCtx->srcEnd = pSrc + srcSize;
    pCtx->offset = 31;

} // void InitializeDecBitStream(AVS_BIT_STREAM_CONTEXT *pCtx,

inline
Ipp32u GetBit(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    Ipp32u res;

    // get 1 bit
    res = *(pCtx->src);
    res = (res >> pCtx->offset) & 1;

    // update variables
    pCtx->offset -= 1;
    if (0 > pCtx->offset)
    {
        pCtx->src += 1;
        pCtx->offset = 31;
    }

    return res;

} // Ipp32u GetBit(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
Ipp32u GetBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)
{
    Ipp32u res;

    // update variables
    pCtx->offset -= iNum;

    if (0 <= pCtx->offset)
    {
        // get bits
        res = *(pCtx->src);
        res = res >> (pCtx->offset + 1);
    }
    else
    {
        pCtx->offset += 32;

        // get bits
        res = pCtx->src[1] >> pCtx->offset;
        res >>= 1;
        res += pCtx->src[0] << (31 - pCtx->offset);

        // advance source pointer
        pCtx->src += 1;
    }

    // mask required bits
    res &= ~(-1 << iNum);

    return res;

} // Ipp32u GetBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)

inline
Ipp32s GetSignedBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)
{
    Ipp32s res;

    res = GetBits(pCtx, iNum);

    // MSB is the sign bits
    // we need to clone it
    res <<= (32 - iNum);
    res >>= (32 - iNum);

    return res;

} // Ipp32s GetSignedBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)

inline
Ipp32u LookUpNextBit(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    return (((*(pCtx->src)) >> pCtx->offset) & 1);

} // Ipp32u LookUpNextBit(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
Ipp32u LookUpNextByte(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    Ipp32u res;

    if (7 <= pCtx->offset)
    {
        // get bits
        res = *(pCtx->src);
        res = res >> (pCtx->offset - 7);
    }
    else
    {
        // get bits
        res = pCtx->src[1] >> (pCtx->offset + 24);
        res >>= 1;
        res += pCtx->src[0] << (7 - pCtx->offset);
    }

    // mask required bits
    res &= 0x0ff;

    return res;

} // Ipp32u LookUpNextByte(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
void SkipBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)
{
    pCtx->offset -= iNum;
    if (0 > pCtx->offset)
    {
        pCtx->src += 1;
        pCtx->offset += 32;
    }

} // void SkipBits(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s iNum)

inline
Ipp32u GetExpGolombCode(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    Ipp32s leadingZeroBits = 0;
    Ipp32u CodeNum;

    // calculate leading zeros
    do
    {
        Ipp32u moreZeros;

        // get next byte
        CodeNum = LookUpNextByte(pCtx);

        // get number of leading zeros
        moreZeros = AVSDecMoreZerosTable[CodeNum / 2];

        leadingZeroBits += moreZeros;
        SkipBits(pCtx, moreZeros);

    } while (0 == CodeNum);

    // get code, which fits the scheme 1XXX
    CodeNum = GetBits(pCtx, leadingZeroBits + 1);
    CodeNum = CodeNum - 1;

    return CodeNum;

} // Ipp32u GetExpGolombCode(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
Ipp32u GetUE(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    return GetExpGolombCode(pCtx);

} // Ipp32u GetUE(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
Ipp32s GetSE(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    Ipp32s element;
    Ipp32u CodeNum;
    Ipp32s signExtended;

    // decode Exp-Glolomb code
    CodeNum = GetExpGolombCode(pCtx);

    // create signed element
    element = (CodeNum + 1) >> 1;
    signExtended = (CodeNum & 1) - 1;
    // we use simple scheme of sign restoration,
    // using one ADD and one XOR operation
    element = (element + signExtended) ^ signExtended;

    return element;

} // Ipp32s GetSE(AVS_BIT_STREAM_CONTEXT *pCtx)

inline
Ipp32u GetExpGolombCode(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)
{
    Ipp32s leadingZeroBits = 0;
    Ipp32u CodeNum;

    // calculate leading zeros
    do
    {
        Ipp32u moreZeros;

        // get next byte
        CodeNum = LookUpNextByte(pCtx);

        // get number of leading zeros
        moreZeros = AVSDecMoreZerosTable[CodeNum / 2];

        leadingZeroBits += moreZeros;
        SkipBits(pCtx, moreZeros);

    } while (0 == CodeNum);

    // get code, which fits the scheme 1XXX
    CodeNum = GetBits(pCtx, leadingZeroBits + 1 + order);
    CodeNum = CodeNum - (1 << order);

    return CodeNum;

} // Ipp32u GetExpGolombCode(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)

inline
Ipp32u GetUE(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)
{
    return GetExpGolombCode(pCtx, order);

} // Ipp32u GetUE(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)

inline
Ipp32s GetSE(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)
{
    Ipp32s element;
    Ipp32u CodeNum;
    Ipp32s signExtended;

    // decode Exp-Glolomb code
    CodeNum = GetExpGolombCode(pCtx, order);

    // create signed element
    element = (CodeNum + 1) >> 1;
    signExtended = (CodeNum & 1) - 1;
    // we use simple scheme of sign restoration,
    // using one ADD and one XOR operation
    element = (element + signExtended) ^ signExtended;

    return element;

} // Ipp32s GetSE(AVS_BIT_STREAM_CONTEXT *pCtx, Ipp32s order)

inline
Ipp32s GetBitsLeftToDecode(AVS_BIT_STREAM_CONTEXT *pCtx)
{
    Ipp32s bitsLeft;

    bitsLeft = (Ipp32s) ((pCtx->srcEnd - pCtx->src - 1) * 32);
    bitsLeft += pCtx->offset + 1;

    return bitsLeft;

} // Ipp32s GetBitsLeftToDecode(AVS_BIT_STREAM_CONTEXT *pCtx)

// forward declaration of used types
struct AVS_SEQUENCE_HEADER;
struct AVS_PICTURE_HEADER;
struct AVS_SLICE_HEADER;

// declaration of headers' parsing routines
extern
bool DecodePicHeader(AVS_PICTURE_HEADER *pPicHeader,
                     AVS_BIT_STREAM_CONTEXT *pCtx,
                     const AVS_SEQUENCE_HEADER *pSeqHeader);
extern
bool DecodeSlcHeader(AVS_SLICE_HEADER *pSlcHeader,
                     AVS_BIT_STREAM_CONTEXT *pCtx,
                     const AVS_SEQUENCE_HEADER *pSeqHeader,
                     const AVS_PICTURE_HEADER *pPicHeader);

} // namespace UMC

#endif // __UMC_AVS_DEC_BIT_STREAM_H
